#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time      :2021/4/16 14:22
# @Author    :cjw
import time
from common.browser import CHROME, Remote
from selenium.webdriver.support.wait import WebDriverWait
from setting.setting import BY_RULES, WEBDRIVER_WAIT_TIMEOUT
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from common.logs import log


class Page:
	"""页面基类：采用页面实例化的方式"""
	url = None
	browser = CHROME
	locators = {}  # 元素定位器

	def __init__(self, is_remote: bool = True):
		"""
		:param is_remote: 远程启动参数
		"""
		if is_remote:
			self.driver = self.browser(browser_type=Remote).browser
		else:
			self.driver = self.browser().browser

	def __getattr__(self, item):
		"""
		当使用实例.属性获取属性值时，如果实例没有该属性，就会调用这个方法
		用于实例属性访问，获取locators元素定位器中的值
		:param item:
		:return:
		"""
		if item not in self.locators:
			raise Exception(f'元素定位器locators中无定位属性的键：{item}')

		by, val = self.locators[item]
		if by not in BY_RULES:
			raise Exception(f'不支持该定位方式：{by}')
		log.info(f'元素定位方式：{by}, 定位内容：{val}')
		element = WebDriverWait(self.driver, WEBDRIVER_WAIT_TIMEOUT).until(
			lambda x: x.find_element(by, val))
		return element

	def element(self, loc: tuple, timeout: int = 2):
		"""
		定位元素方法
		:param loc:
		:return:
		"""
		log.info(f'元素定位方式：{loc[0]}, 定位内容：{loc[1]}')
		element = WebDriverWait(self.driver, timeout).until(
			EC.visibility_of_element_located(loc))
		return element

	def elements(self, loc: tuple):
		"""
		定位元素方法
		:param loc:
		:return:
		"""
		log.info(f'元素定位方式：{loc[0]}, 定位内容：{loc[1]}')
		element = WebDriverWait(self.driver, WEBDRIVER_WAIT_TIMEOUT).until(
			EC.visibility_of_all_elements_located(loc))
		return element

	def click_or_script_click(self, element):
		"""
		按钮点击,点击的元素上面还有别的东西覆盖，将改成js点击
		:param element: 定位的元素
		:return:
		"""
		try:
			element.click()
		except Exception:
			self.driver.execute_script('arguments[0].click();', element)

	def clear_and_send_keys(self, element, value, mode: str = 'control_a'):
		"""
		清空输入框内容，再输入内容
		:param element: 定位的元素
		:param value: 输入的值
		:param mode: 输入方式 double_click, control_a, js
		:return:
		"""
		if mode == 'control_a':
			# 通过键盘全选，然后直接输入新的内容，就不用clear了
			element.send_keys(Keys.CONTROL, 'a')
			element.send_keys(value)
		elif mode == 'js':
			# 使用js输入
			self.driver.execute_script('arguments[0].value = "";', element)
			self.driver.execute_script('arguments[0].value = "{}";'.format(value), element)
		else:
			element.clear()
			element.send_keys(value)

# @staticmethod
# def checkpoint(case_self, text: str, mode: int = 1, poll_frequency=0.2, timeout=2):
# 	"""
# 	检查点
# 	:param case_self: 检查的文本
# 	:param text: 检查的文本
# 	:param mode: 检查的方式，1：包含检查，2：相等检查
# 	:param poll_frequency: 检查频率
# 	:param timeout: 检查超时时间
# 	:return:
# 	"""
# 	screen = None
# 	stacktrace = None
# 	end_time = time.time() + timeout
# 	while True:
# 		try:
# 			if mode == 1:
# 				case_self.assertIn(text, case_self.driver.page_source, f'网页中不包含检查内容：{text}')
# 		except AssertionError as exc:
# 			screen = getattr(exc, 'screen', None)
# 			stacktrace = getattr(exc, 'stacktrace', None)
# 		time.sleep(poll_frequency)
# 		if time.time() > end_time:
# 			break
# 	raise TimeoutException(f'检查内容：{text}，超时', screen, stacktrace)
